package ru.picman.util;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

public class GreenThreadProcessor
{
	public GreenThreadProcessor() {
		this.queue = new PriorityQueue<GreenThreadWakeup>(16,new GreenThreadWakeupComparator());
	}
	
	public void start(GreenThread thread) {
		this.queue.add(new GreenThreadWakeup(thread,0L));
		thread.setRunning(true);
	}
	
	public boolean tick(long now) {
		final List<GreenThreadWakeup> rescheduled = new ArrayList<GreenThreadWakeup>();
		try {
			while (true) {
				GreenThreadWakeup wakeup = this.queue.peek();
				if (wakeup == null)
					return !rescheduled.isEmpty();
				
				if (wakeup.timestamp > now)
					return true;
				
				if (this.queue.poll() != wakeup)
					throw new IllegalStateException();
				
				wakeup.thread.run();
				long sleep = wakeup.thread.getSleepTime();
				if (sleep == GreenThread.EOF) {
					wakeup.thread.setRunning(false);
					continue;
				}
				
				wakeup.timestamp = now + sleep;
				rescheduled.add(wakeup);
			}
		}
		finally {
			queue.addAll(rescheduled);
			rescheduled.clear();
		}
	}
	
	private final PriorityQueue<GreenThreadWakeup> queue;
	
	//
	
	private static class GreenThreadWakeup
	{
		public GreenThreadWakeup(GreenThread thread, long timestamp) {
			this.thread = thread;
			this.timestamp = timestamp;
		}
		
		public final GreenThread thread;
		public long              timestamp;
	}
	
	//
	
	private static class GreenThreadWakeupComparator
	            implements Comparator<GreenThreadWakeup>
	{
		
		public int compare(GreenThreadWakeup o1, GreenThreadWakeup o2) {
			int val = Long.signum(o1.timestamp - o2.timestamp);
			return (val == 0) ? 1 : val;
		}
	}
}
